edit.js ➔ process_update_request   A
last analyzed

Complexity

Conditions 4

Size

Total Lines 23
Code Lines 15

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 15
dl 0
loc 23
rs 9.65
c 0
b 0
f 0
cc 4
1
$(document).ready(function() {
2
    $('#reverse').on('click', function() {
3
        var entries = $('#item_container > div').not('.entry-template').detach();
4
        $('#item_container').prepend($(entries.get().reverse()));
5
    });
6
    $('.existing-entry').each(function(index, item) {
7
        $(item).data('saved_values', {
8
            position: index,
9
            title: $(item).find('.title input').val(),
10
            description: $(item).find('.description textarea').val()
11
        });
12
    });
13
    $('#upload_field').on('change', function() {
14
        var image, entry, reader,
15
            entry_template = $('#item_container .entry-template')[0];
16
17
        $.each(this.files, function(index, file) {
18
            if (!file.type.match(/image.*/)) {
19
                // this file is not an image. TODO: Report an error?
20
                return;
21
            }
22
23
            image = document.createElement('img');
24
            image.file = file;
25
            reader = new FileReader();
26
            reader.onload = (function(img) { return function(e) {img.src = e.target.result;};})(image);
27
            reader.readAsDataURL(file);
28
29
            entry = $.clone(entry_template);
30
            $(entry)
31
                .removeClass('entry-template')
32
                .addClass('new-entry');
33
            $('.thumbnail', entry).prepend(image);
34
            $('.filename', entry).text(file.name);
35
36
            $('#item_container').prepend(entry);
37
        });
38
    });
39
    $('#item_container')
40
        .on('click', '.image-delete', function(e) {
41
            e.stopPropagation();
42
            var entry = $(this).closest('.entry');
43
            if (entry.hasClass('new-entry')) {
44
                entry.remove();
45
            } else {
46
                entry.addClass('entry-deleted');
47
            }
48
        })
49
        .on('click', '.image-cancel-delete', function(e) {
50
            e.stopPropagation();
51
            $(this).closest('.entry').removeClass('entry-deleted');
52
        })
53
        .on('click', '.entry', function() {
54
            var viewer = $('#entry-viewer');
55
56
            if ($(this).find('.thumbnail img').data('originalUrl')) {
57
                viewer.find('.image').html('<img src="' + $(this).find('.thumbnail img').data('originalUrl') + '" />');
58
            } else {
59
                viewer.find('.image').html($(this).find('.thumbnail img').clone());
60
            }
61
            viewer.find('.title input')
62
                .val($(this).find('.title input').val());
63
            viewer.find('.description textarea').val($(this).find('.description textarea').val());
64
            viewer.find('.filename').text($(this).find('.filename').text());
65
            if (!viewer.hasClass('active')) {
66
                viewer.addClass('active');
67
            }
68
            viewer.data('active', this.id);
69
            $('.entry.active').removeClass('active');
70
            $(this).addClass('active');
71
        })
72
        .sortable();
73
74
    $('#entry-viewer').on('blur', '.title input, .description textarea', function() {
75
        var viewer = $('#entry-viewer'),
76
        active = viewer.data('active');
77
        if (active !== undefined) {
78
            $('#' + active).find('.title input').val(viewer.find('.title input').val());
79
            $('#' + active).find('.description textarea').val(viewer.find('.description textarea').val());
80
        }
81
    });
82
83
    $('#save_all').on('click', function() {
84
        var delete_guids = [],
85
            update_items = [],
86
            fd, xhr,
87
            label = $('#progress_bar .progress-label'),
88
            progressbar = $('#progress_bar'),
89
            progress_dialog = $('#progress_dialog'),
90
            pending_requests = [];
91
92
        $('#progress_total').text('0');
93
        $('#progress_completed').text('0');
94
        $('#progress_filesize_total').text('');
95
96
        progressbar
97
            .data('pending', 0)
98
            .data('filesize', 0)
99
            .data('total', 0);
100
101
        function close_dialog() {
102
            if (progressbar.data('pending') < 1) {
103
                progress_dialog.dialog('close');
104
            }
105
        }
106
107
        function create_entry(index, item) {
108
            var file =  $(item).find('.thumbnail img')[0].file,
109
                xhr = new XMLHttpRequest(),
110
                fd = new FormData();
111
112
            // todo: This has to be supported by server side
113
            xhr.upload.addEventListener("progress", function(e) {
114
                if (e.lengthComputable) {
115
                    var delta = e.loaded - $(item).data('completed'),
116
                    completed = $('#progress_bar').data('filesize_completed') + delta;
0 ignored issues
show
Unused Code introduced by
The variable completed seems to be never used. Consider removing it.
Loading history...
117
                }
118
            }, false);
119
120
            fd.append("title", $(item).find('.title input').val());
121
            fd.append("description", $(item).find('.description textarea').val());
122
            fd.append('image', file);
123
            fd.append("position", index);
124
            fd.append("operation", 'create');
125
126
            xhr.onreadystatechange = function() {
127
                if (xhr.readyState === 4) {
128
                    try {
129
                        var reply = JSON.parse(xhr.responseText);
130
                        if (!reply.success) {
131
                            $.midcom_services_uimessage_add({type: 'error', message: reply.error, title: reply.title});
132
                        } else {
133
                            $(item)
134
                                .removeClass('new-entry')
135
                                .addClass('existing-entry')
136
                                .attr('id', 'image-' + reply.guid)
137
                                .data('saved_values', {
138
                                    position: reply.position,
139
                                    title: $(item).find('.title input').val(),
140
                                    description: $(item).find('.description textarea').val()
141
                                })
142
                                .find('.filename').text(reply.filename);
143
                        }
144
                    } catch (e) {
145
                        $.midcom_services_uimessage_add({type: 'error', message: e.message, title: e.name});
146
                    }
147
                    remove_pending_request();
148
                }
149
            };
150
            add_pending_request(xhr, fd);
151
            $('#progress_bar').data('filesize', $('#progress_bar').data('filesize') + file.size);
152
153
            function format_filesize(size) {
154
                var i = 0,
155
                    units = ['B', 'KB', 'MB', 'GB'];
156
157
                while (size > 1024) {
158
                    size = size / 1024;
159
                    i++;
160
                }
161
162
                return Math.max(size, 0.1).toFixed(1) + ' ' + units[i];
163
            }
164
165
            $('#progress_filesize_total').text(format_filesize($('#progress_bar').data('filesize')));
166
        }
167
168
        function update_entry(index, item) {
169
            var entry = {},
170
                title = $(item).find('.title input').val(),
171
                description = $(item).find('.description textarea').val(),
172
                saved_values = $(item).data('saved_values');
173
174
            if (   title === saved_values.title
175
                && description === saved_values.description
176
                && index === saved_values.position) {
177
                return;
178
            }
179
180
            entry.title = title;
181
            entry.description = description;
182
            entry.position = index;
183
            entry.guid = item.id.slice(6);
184
185
            update_items.push(entry);
186
        }
187
188
        function add_pending_request(xhr, fd) {
189
            var pending = $('#progress_bar').data('pending') + 1,
190
                total = $('#progress_bar').data('total') + 1;
191
192
            $('#progress_bar')
193
                .data('pending', pending)
194
                .data('total', total);
195
            $('#progress_total').text(total);
196
197
            xhr.open("POST", window.location.href + 'ajax/');
198
            pending_requests.push({xhr: xhr, fd: fd});
199
        }
200
201
        function remove_pending_request() {
202
            var pending = $('#progress_bar').data('pending') - 1,
203
                total = $('#progress_bar').data('total'),
204
                completed = total - pending;
205
206
            $('#progress_bar')
207
                .data('pending', pending)
208
                .progressbar('value', Math.round((completed / total) * 100));
209
            $('#progress_completed').text(completed);
210
        }
211
212
        function process_pending_requests() {
213
            pending_requests.forEach(function(request) {
214
                request.xhr.send(request.fd);
215
            });
216
        }
217
218
        function process_update_request() {
219
            var xhr = new XMLHttpRequest(),
220
                fd = new FormData();
221
222
            fd.append("items", JSON.stringify(update_items));
223
            fd.append("operation", 'batch_update');
224
225
            xhr.onreadystatechange = function() {
226
                if (xhr.readyState === 4) {
227
                    remove_pending_request();
228
                    update_items.forEach(function(item) {
229
                        $('#image-' + item.guid).data('saved_values', {
230
                            position: item.position,
231
                            title: item.title,
232
                            description: item.description
233
                        });
234
                    });
235
                    update_items = [];
236
                }
237
            };
238
239
            add_pending_request(xhr, fd);
240
        }
241
242
        $('#item_container .entry-deleted').each(function(index, item) {
243
            if ($(item).hasClass('new-entry')) {
244
                $(item).remove();
245
                return;
246
            }
247
            delete_guids.push(item.id.slice(6));
248
        });
249
250
        if (delete_guids.length > 0) {
251
            fd = new FormData();
252
            xhr = new XMLHttpRequest();
253
254
            fd.append("guids", delete_guids.join('|'));
255
            fd.append("operation", 'delete');
256
            xhr.onreadystatechange = function() {
257
                if (xhr.readyState === 4) {
258
                    $('#item_container .entry-deleted').remove();
259
                    remove_pending_request();
260
                }
261
            };
262
            add_pending_request(xhr, fd);
263
        }
264
265
        $('#item_container .entry:not(.entry-template):not(.entry-deleted)').each(function(index, item) {
266
            if ($(item).hasClass('new-entry')) {
267
                create_entry(index, item);
268
            } else {
269
                update_entry(index, item);
270
            }
271
        });
272
        if (update_items.length > 0) {
273
            process_update_request();
274
        }
275
276
        progressbar
277
            .progressbar({
278
                value: false,
279
                change: function() {
280
                    if (progressbar.progressbar('value') !== false) {
281
                        label.text(progressbar.progressbar('value') + '%');
282
                    }
283
                },
284
                complete: function() {
285
                    window.setTimeout(close_dialog, 1000);
286
                }
287
            });
288
        progress_dialog.dialog({
289
            autoOpen: true,
290
            modal: true,
291
            open: function() {
292
                process_pending_requests();
293
            },
294
            close: function() {
295
                progressbar.progressbar('value', false);
296
                label.text('');
297
            }
298
        });
299
    });
300
});
301